Skip to content
forked from 0xE111/cat-400

Game framework for nim programming language. Modular and extensible

License

Notifications You must be signed in to change notification settings

yamatakeru/cat-400

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

60 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Cat-400

"Cat-400" (c4) is a game framework for Nim programming language. Being a framework means that c4 will do all the dirty job for you while you focus on creating your game. Under active development.

List of other nim game engines/frameworks

Link Comments
https://github.com/yglukhov/rod No docs
https://github.com/zacharycarter/zengine
https://github.com/Vladar4/nimgame2
https://github.com/ftsf/nico
https://github.com/rnentjes/nim-ludens
https://github.com/dustinlacewell/dadren
https://github.com/Polkm/nimatoad
https://github.com/sheosi/tart
https://github.com/copygirl/gaem X
https://github.com/dadren/dadren X
https://github.com/fragworks/frag X
https://github.com/hcorion/Jonah-Engine X
https://github.com/jsudlow/cush X
https://github.com/def-/nim-platformer X
https://github.com/Vladar4/nimgame X

Brief overview

C4 is being developed for custom needs. Please note that it's more educational project rather then professional software, however if you like it you may use it and make contributions.

The main benefit of c4 is its documentation - I try to make code and docs changes side by side, so docs should always be up-to-date. This is the thing many projects lack.

★ Your help required!

C4 tries to be clear and well-designed. Your contribution is highly appreciated! Sometimes even an idea or better design/implementation would be very helpful. Check out current issues.

Tutorial

Learn by coding your first game with c4! Less words - let's try to build something.

Install & display version

First, install latest c4 right from github:

nimble install https://github.com/c0ntribut0r/cat-400@#head

Create test project.

mkdir /tmp/test
cd /tmp/test
touch main.nim

Now edit main.nim. Let's just launch plain c4 without any custom code.

from c4.core import run

when isMainModule:
  run()

Check whether you can launch c4 and show version:

nim c -r main.nim -v
...
Nim version 0.17.3
Framework version 0.1.1-12
Project version 0.0

Our main.nim looks empty, but the main job is done under the hood when calling run(). C4 initializes loggers, splits process into client and server, launches infinite loops and does many other things. We don't have to implement it ourselves which lets us focus on really important things! You may have a look at options which are available for your app by default:

./main -h

Now let's start customizing.

Framework configuration

Configuring c4 is nothing more than changing a tuple. The framework uses some reasonable defaults for your project's config (like version: "0.0") but sometimes we'll need to change them. Oh, let's start with version:

from c4.core import run
from c4.conf import config

config.version = "0.1"

when isMainModule:
  run()

Now nim c -r main.nim -v will say that our project version is 0.1 which is better than default 0.0. Well, now you know almost everything you need to create your game.

Client-server

C4 uses client-server architecture. This means that unlike other nim game engines, c4 launches two separate processes (not threads!), one for client and the other for server. Client does all the job for displaying graphics and UI, playing audio and reading user input. Server does the real job - it launches world simulation, handles physics, processes user input etc.

Important fact is that server is always launched. Even if you play a single player mode, your client is still connecting to a local server on the same machine. If you connect to remote host, you may use your local server for client-side prediction (which is an advanced topic).

C4 allows you to launch your app in a "headless mode" - just a server without a client. This is useful if you want to launch your custom server on VPS or so and you don't need the client at all. We will also use this mode during first steps so that we don't have to care about the client. Use -s flag to launch server only. You will see something like this (output may vary depending on c4 version):

nim c -r main.nim --loglevel=DEBUG -s
...
[2018-01-10T21:48:07] SERVER DEBUG: Version 0.1.1-19
[2018-01-10T21:48:07] SERVER DEBUG: Starting server
[2018-01-10T21:48:07] SERVER DEBUG: Server is Loading
[2018-01-10T21:48:07] SERVER DEBUG: EnetNetworkSystem init
[2018-01-10T21:48:07] SERVER DEBUG: Server is Running

Quit with ctrl+C. Note that we passed --loglevel flag to the executable so that we can better know what's going on under the hood.

We haven't defined any specific behavior, so server just runs by default. Now it's time for "hello world" program!

States

States are something you'll find very helpful while building your app. Explaing what State is would be a redundand job - just go to excellent Robert Nystrom's website: http://gameprogrammingpatterns.com/state.html.

C4 relies heavily on states. You will see (and hopefully use) it very often. Let's see an example right now.

C4 has a Server object. Let's omit its internals and just focus on its state property:

type
  Server = object of RootObj
    state: ref State
    # ...

Server may be in several reasonable states, like None (unitialized), Loading (initializing internals), Running (running subsystems) etc:

type
  None* = object of State
  Loading* = object of State
  Running* = object of State

Each state not only represents what an object is doing, but also allows to perform some state-related actions. For example, when Server enters Loading state it initializes all its subsystems; when Server enters Running it launches infinite game loop.

Now let's be destructive and make server just output "hello world" instead of launching that boring game loop! Create new folder for server-related code:

mkdir server
touch server/states.nim

Edit states.nim and define a transition to Loading state. Transition is defined by switch method like this:

import c4.utils.state
import c4.server
from logging import nil


method switch*(self: var ref State, newState: ref Running, instance: ref Server) =
  # this method will shadow default server's one (which is not a good idea)
  if self of ref Loading:  # if we came from Loading state
    self = newState  # actually swich current (Loading) state to Running
    echo("Hello world")

If we now compile our code we'll see no changes:

nim c -r main.nim --loglevel=DEBUG -s
...
[2018-01-10T22:46:53] SERVER DEBUG: Version 0.1.1-19
[2018-01-10T22:46:53] SERVER DEBUG: Starting server
[2018-01-10T22:46:53] SERVER DEBUG: Server is Loading
[2018-01-10T22:46:53] SERVER DEBUG: EnetNetworkSystem init
[2018-01-10T22:46:53] SERVER DEBUG: Server is Running

That's because c4 doesn't see our custom transition definition. Let's fix this by importing our state module before calling run():

from c4.core import run
from c4.conf import config
import server.server_states

config = (
  version: "0.1"
)

when isMainModule:
  run()
nim c -r main.nim --loglevel=DEBUG -s
...
[2018-01-10T22:48:25] SERVER DEBUG: Version 0.1.1-19
[2018-01-10T22:48:25] SERVER DEBUG: Starting server
[2018-01-10T22:48:25] SERVER DEBUG: Server is Loading
[2018-01-10T22:48:25] SERVER DEBUG: EnetNetworkSystem init
Hello world

Nice! We just broke our server startup in favor of "Hello world" output. Now revert the destructive changes and go on.

Warning: Avoid calling switch inside of switch. If your state graph is cyclic (i.e. you may switch to already visited states) you may face stack overflow error.

About

Game framework for nim programming language. Modular and extensible

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Nim 69.5%
  • C 30.4%
  • Shell 0.1%