Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

14 how to play popup #27

Merged
merged 10 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions HOW_TO_PLAY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# How to play πŸ“•

- The game is played in a 35x35 grid.
- The player starts as a single **cell** snake with a random direction.
- The player can navigate the snake via W, A, S, D keys or the arrow keys (⬆, β¬…, ⬇, ➑).
- The player needs to navigate the snake to the snack in order to have the snake grow and gain score.
- Each eaten snack contributes 1 point to the score.
- If the snake hits its own tail, then the game is over.
- Rules of "Play without borders":
- If the snake hits the grid borders, it will continue to move in the same direction from the opposite end.
- Rules of "Play with borders":
- If the snake hits the grid boundaries, then the game is over.
15 changes: 3 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,9 @@
<img src="https://img.shields.io/twitter/follow/dev_ekinkaradag?style=social&logo=twitter" alt="follow on Twitter"></a>
</p>

## Rules πŸ“•

- The game is played in a 35x35 grid.
- The player starts as a single **cell** snake with a random direction.
- The player can navigate the snake via W, A, S, D keys or the arrow keys (⬆, β¬…, ⬇, ➑).
- The player needs to navigate the snake to the snack in order to have the snake grow and gain score.
- Each eaten snack contributes 1 point to the score.
- If the snake hits its own tail, then the game is over.
- Rules of "Play without borders":
- If the snake hits the grid borders, it will continue to move in the same direction from the opposite end.
- Rules of "Play with borders":
- If the snake hits the grid boundaries, then the game is over.
## How to play πŸ“•

If you'd like to know about how to play the game, you can find about it here: [`HOW_TO_PLAY.md`](https://github.com/ekinkaradag/snake-vue3/blob/14-how-to-play-popup/HOW_TO_PLAY.md)

## Development πŸ‘¨β€πŸ’»

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
"build": "vite build",
"preview": "vite preview",
"deploy": "gh-pages -d dist",
"typecheck": "vue-tsc --noEmit"
"typecheck": "vue-tsc --noEmit --skipLibCheck"
},
"dependencies": {
"marked": "^7.0.4",
"typescript": "^5.1.6",
"vue": "^3.3.4",
"vuex": "^4.1.0"
Expand Down
49 changes: 39 additions & 10 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,23 @@
<div class="disclaimer">Β© Copyright 2023 Ekin Karadag</div>
</div>
<h1 class="title">SNAKE</h1>
<v-button
v-if="!isPlaying"
@click="openPopup"
title="How to play"
class="button"
/>
<v-button
v-if="!isPlaying"
@click="onStartGame(gameRuleWithoutBorders)"
title="Play without borders"
class="button-play"
class="button button-play"
/>
<v-button
v-if="!isPlaying"
@click="onStartGame(gameRuleWithBorders)"
title="Play with borders"
class="button-play"
class="button button-play"
/>
<v-button
v-else
Expand All @@ -25,6 +31,7 @@
}"
title="Stop"
/>
<v-how-to-play-popup v-if="isShowingHowToPlayPopup" @closed="closePopup" />
<v-playground :score="score" />
<div class="footer">
<v-social-links class="social-links" />
Expand All @@ -40,14 +47,21 @@
</template>

<script lang="ts">
import { computed, onMounted, onBeforeUnmount, type ComputedRef } from "vue";
import {
computed,
onMounted,
onBeforeUnmount,
type ComputedRef,
ref,
} from "vue";
import { useStore } from "vuex";
import { areSameCoordinates, isSnake } from "@/utils/index";
import { Direction, GameRule } from "@/store/enums";
import type { ICoordinate, ISnack, ISnake } from "@/store/interfaces";

// Components
import VButton from "@/components/Button.vue";
import VHowToPlayPopup from "@/components/HowToPlayPopup.vue";
import VGrid from "@/components/Grid.vue";
import VPlayground from "@/components/Playground.vue";
import VSocialLinks from "@/components/SocialLinks.vue";
Expand Down Expand Up @@ -83,8 +97,9 @@ export default {
name: "App",

components: {
VGrid,
VButton,
VHowToPlayPopup,
VGrid,
VPlayground,
VSocialLinks,
},
Expand Down Expand Up @@ -118,12 +133,16 @@ export default {
() => store.state.snake?.coordinates?.length - 1
);
const tickRate: ComputedRef<number> = computed(() => store.state.tickRate);
const isShowingHowToPlayPopup = ref<boolean>(false);

// Interval variable (It will only run once)
let interval = setInterval(() => {
clearInterval(interval);
}, 1);

// Generate an empty grid to be displayed at the startup
generateGrid();

function getRandomNumber(min: number, max: number) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
Expand Down Expand Up @@ -244,6 +263,14 @@ export default {
}
}

function openPopup() {
if (!isShowingHowToPlayPopup.value) isShowingHowToPlayPopup.value = true;
}

function closePopup() {
if (isShowingHowToPlayPopup.value) isShowingHowToPlayPopup.value = false;
}

function onStartGame(gameRule: GameRule) {
onStopGame();
generateInitials();
Expand Down Expand Up @@ -274,25 +301,27 @@ export default {
gameRuleWithBorders,
isPlaying,
score,
isShowingHowToPlayPopup,
openPopup,
closePopup,
onStartGame,
onStopGame,
};
},
};
</script>
<style>
body {
background-color: black;
}

<style lang="postcss" scoped>
.page {
width: 100%;
text-align: center;
}

.button-play {
.button {
margin: 0 10px;
margin-bottom: 20px;
}

.button-play {
width: 190px;
}

Expand Down
17 changes: 13 additions & 4 deletions src/components/Button.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,18 @@ button {
background-color: #27ae60;
border-radius: 8px;
border-style: none;
box-shadow: rgba(39, 174, 96, 0.15) 0 4px 9px;
box-shadow: #27ae6026 0 4px 9px;
box-sizing: border-box;
color: #fff;
cursor: pointer;
display: inline-block;
font-family: Inter, -apple-system, system-ui, "Segoe UI", Helvetica, Arial,
font-family:
Inter,
-apple-system,
system-ui,
"Segoe UI",
Helvetica,
Arial,
sans-serif;
font-size: 16px;
font-weight: 600;
Expand All @@ -51,7 +57,10 @@ button {
touch-action: manipulation;
vertical-align: top;
white-space: nowrap;
text-shadow: -1px -1px 0 #032b13, 1px -1px 0 #032b13, -1px 1px 0 #032b13,
text-shadow:
-1px -1px 0 #032b13,
1px -1px 0 #032b13,
-1px 1px 0 #032b13,
1px 1px 0 #032b13;
}

Expand All @@ -68,6 +77,6 @@ button:active {
}

button:hover {
box-shadow: rgba(56, 250, 137, 0.2) 0 6px 12px;
box-shadow: #38fa8933 0 6px 12px;
}
</style>
6 changes: 3 additions & 3 deletions src/components/Cell.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,17 @@ export default {
const isGameOver = computed(() => store.state.playground.isGameOver);

const classNames = computed(() => ({
"grid-cell-snake-head": snake.value.coordinates
"grid-cell-snake-head": snake.value?.coordinates
? isSnake(
[snake.value.coordinates[0]],
props.coordinateX,
props.coordinateY
)
: false,
"grid-cell-snake": snake.value.coordinates
"grid-cell-snake": snake.value?.coordinates
? isSnake(snake.value.coordinates, props.coordinateX, props.coordinateY)
: false,
"grid-cell-snack": snack.value.coordinate
"grid-cell-snack": snack.value?.coordinate
? isSnack(props.coordinateX, props.coordinateY, snack.value)
: false,
"grid-cell-game-over": isGameOver.value,
Expand Down
46 changes: 46 additions & 0 deletions src/components/HowToPlayPopup.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<template>
<v-popup @closed="$emit('closed')">
<template #description>
<div v-html="howToPlayMarkdownHTML"></div>
</template>
</v-popup>
</template>

<script lang="ts">
import VPopup from "@/components/Popup.vue";
import { marked } from "marked";
import { computed, ref } from "vue";
export default {
components: {
VPopup,
},
setup() {
const url =
"https://api.github.com/repos/ekinkaradag/snake-vue3/contents/HOW_TO_PLAY.md";
var myRequest = new Request(url, {
headers: new Headers({ accept: "application/vnd.github.v3.raw" }),
});
const howToPlayMarkdownContent = ref<string>("Loading...");
fetch(myRequest)
.then((response: Response) => {
if (response.ok) return response.text();
throw new Error(
"**There was error fetching the [`HOW_TO_PLAY.md`](https://api.github.com/repos/ekinkaradag/snake-vue3/contents/HOW_TO_PLAY.md) from [the GitHub Repo](https://github.com/ekinkaradag/snake-vue3). The server might not be reachable.**"
);
})
.catch((error: Error) => {
return error.message;
})
.then((text: string) => {
howToPlayMarkdownContent.value = text;
});

const howToPlayMarkdownHTML = computed(() =>
marked(howToPlayMarkdownContent.value)
);
return {
howToPlayMarkdownHTML,
};
},
};
</script>
6 changes: 3 additions & 3 deletions src/components/Playground.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<template>
<div class="container">
<div v-show="score >= 0" class="score-area score">
Score:
<code class="score-value">{{ score }}</code>
<div class="score-area score">
{{ score >= 0 ? "Score:" : "" }}
<code v-if="score >= 0" class="score-value">{{ score }}</code>
</div>
<div class="game-area">
<v-grid />
Expand Down
Loading