mirror of
https://github.com/tcsenpai/3DSenpai_Engine.git
synced 2025-06-02 22:50:04 +00:00
Initial commit
This commit is contained in:
commit
aa03bf3a21
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
README.pdf
|
||||
|
||||
.luacheckrc
|
BIN
3DSenpai.3dsx
Normal file
BIN
3DSenpai.3dsx
Normal file
Binary file not shown.
104
README.md
Normal file
104
README.md
Normal file
@ -0,0 +1,104 @@
|
||||
# 3DSenpai
|
||||
|
||||
This documentation describes how the 3DSenpai engine works.
|
||||
|
||||
3DSenpai is a 2D (despite the name) engine that manages the logic and the GUI of Nintendo 3DS
|
||||
homebrews that use [Lua Player Plus 3DS engine](https://github.com/Rinnegatamante/lpp-3ds) by [Rinnegatamante](https://rinnegatamante.it/).
|
||||
|
||||
Despite being tought for creating games, it is totally possible to use the engine to create
|
||||
graphical applications (e.g. managing navigation, menus, etc).
|
||||
|
||||
## Attached Example
|
||||
|
||||
The attached example (index.lua) contains a demo application that shows how to use the engine.
|
||||
Feel free to use it as a reference and a starting point for your applications.
|
||||
|
||||
## Global objects
|
||||
|
||||
To better manage the workflow of the game, some global objects are created at runtime and
|
||||
are accessed during the game loop.
|
||||
|
||||
### Program
|
||||
|
||||
This object contains informations about the game such as author, version, title and so on.
|
||||
|
||||
### emptyElement
|
||||
|
||||
This object is a prototype of an empty element that is used to initialize an element and standardize its properties.
|
||||
|
||||
### Scene
|
||||
|
||||
This object contains the character object, the currentScene property, the imagesToDraw table
|
||||
and the environment object.
|
||||
|
||||
#### Scene.environment
|
||||
|
||||
This is the most important object of the scene. It represents every pixel as a tile and is used to define, determine and manipulate the position and behavior of the elements in the scene.
|
||||
|
||||
It contains a size property with the width and height of the screen and the matrix table which is initialized by the setScene function as a 2D array representing every tile content. It is
|
||||
accessed through:
|
||||
|
||||
Scene.environment.matrix[x][y]
|
||||
|
||||
## initalLoad
|
||||
|
||||
This method is called just after all the variables have been initialized.
|
||||
Normally, you would use it to set the first scene through setScene method and load
|
||||
everything you need to start the game.
|
||||
|
||||
### setScene
|
||||
|
||||
This method accepts a scene method that is called to obtain the desired scene properties.
|
||||
Additionally, it resets the Scene.environment.matrix property to the default values.
|
||||
These properties are then assigned to the Scene.currentScene and Scene.imagesToDraw objects.
|
||||
|
||||
### Scene methods
|
||||
|
||||
These methods are to be created by the developer.
|
||||
For setScene to be effective, the scene method should return a table containing two booleans
|
||||
that define whether or not the background and the main character should be drawn, and a table containing every element that should be drawn.
|
||||
|
||||
## The main loop
|
||||
|
||||
The game engine revolves around a mainLoop function that keep calling
|
||||
keyEvents and mainGUI functions.
|
||||
|
||||
## keyEvents
|
||||
|
||||
This function keep the inputs monitored for key events and react consequently.
|
||||
|
||||
## mainGUI
|
||||
|
||||
This function loads the Scene object and, if specified, draws both the background and
|
||||
the main character.
|
||||
|
||||
Then, if any, it parses the Scene.imagesToDraw table and draws the elements images that
|
||||
are specified in it.
|
||||
|
||||
## Elements methods
|
||||
|
||||
These methods are a set of functions that help the developer create, manage and inspect elements in the current scene.
|
||||
|
||||
### isElement
|
||||
|
||||
This function returns wheter or not an element covers the specified coordinates (x and y).
|
||||
A boolean is returned.
|
||||
|
||||
### elementPosition
|
||||
|
||||
If an element is in the elementsTable table, it returns the element object. Else, it returns nil.
|
||||
|
||||
### placeElement
|
||||
|
||||
This function is used to place an element in the scene.
|
||||
It checks whether the element is already placed and if the tiles that should be covered are free
|
||||
or not.
|
||||
It returns a boolean and a string containing the result of the operation.
|
||||
|
||||
### removeElement
|
||||
|
||||
This function removes an element from the scene by checking its existence and position through the elementsTable and the the scene environment.Matrix.
|
||||
|
||||
### checkTileCollision
|
||||
|
||||
Given a set of coordinates (x and y), this function checks whether there is an element that covers the specified coordinates and if the element has the Collision property set to true.
|
BIN
assets/character.png
Normal file
BIN
assets/character.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
227
index.lua
Normal file
227
index.lua
Normal file
@ -0,0 +1,227 @@
|
||||
Screen.disable3D() --Disabling 3D for the top screen
|
||||
|
||||
-- SECTION Program object
|
||||
local Program = {
|
||||
title = "3DSenpai",
|
||||
dir = "0_LPP_Test"
|
||||
}
|
||||
-- !SECTION Program object
|
||||
|
||||
-- SECTION Misc objects
|
||||
local emptyElement = {
|
||||
Element = nil, -- name of the element
|
||||
Type = 0, -- 0 = empty, 1 = element, 2 = creature, 3 = object
|
||||
Collision = false, -- true / false
|
||||
Size = { 0, 0 }, -- Size of the element
|
||||
StartingPosition = { 0, 0 }, -- Starting position of the element
|
||||
Image = nil, -- Image of the element (object)
|
||||
Screen = TOP_SCREEN, -- Screen of the element
|
||||
Properties = {} -- Properties of the element (e.g. health, damage, etc.)
|
||||
}
|
||||
|
||||
local elementsTable = {} -- {name = {x,y}}
|
||||
-- !SECTION Misc objects
|
||||
|
||||
-- SECTION Elements object
|
||||
local Scene = {
|
||||
environment = {
|
||||
size = { x = 400, y = 240 },
|
||||
matrix = {}
|
||||
},
|
||||
character = {
|
||||
image = "assets/character.png",
|
||||
imageLoaded = nil,
|
||||
position = { x = 176, y = 96 }
|
||||
},
|
||||
currentScene = nil, -- Current scene method
|
||||
imagesToDraw = {} -- A table containing the images to draw each frame
|
||||
}
|
||||
-- !SECTION Elements object
|
||||
|
||||
-- SECTION Scenes
|
||||
-- Scenes are functions that are called to draw the scene on the screen at the
|
||||
-- beginning of the program or when the user changes the scene (e.g. next level)
|
||||
local firstLevel = function ()
|
||||
local isBackground = true
|
||||
local isCharacter = true
|
||||
local imagesToDraw = {}
|
||||
return {isBackground, isCharacter}, imagesToDraw
|
||||
end
|
||||
-- !SECTION Scenes
|
||||
|
||||
local setScene = function (scene) -- Sets the current scene method
|
||||
-- Reset the environment matrix
|
||||
for i = 1, Scene.environment.size.x do
|
||||
Scene.environment.matrix[i] = {}
|
||||
-- Each pixel of the environment contains the informations about the element on it (if any)
|
||||
for j = 1, Scene.environment.size.y do
|
||||
Scene.environment.matrix[i][j] = {emptyElement}
|
||||
end
|
||||
end
|
||||
local settings = scene() -- Call the scene method that returns settings and images to draw
|
||||
Scene.currentScene = settings[0]
|
||||
Scene.imagesToDraw = settings[1]
|
||||
return true
|
||||
end
|
||||
|
||||
local initialLoad = function ()
|
||||
System.currentDirectory("/3ds/" .. Program.dir .. "/")
|
||||
Scene.character.imageLoaded = Screen.loadImage(System.currentDirectory()
|
||||
.. Scene.character.image)
|
||||
-- Setting the first scene
|
||||
setScene(firstLevel)
|
||||
end
|
||||
|
||||
-- SECTION Controls check
|
||||
local keyEvents = function ()
|
||||
local pad = Controls.read() -- Read Controls
|
||||
if (Controls.check(pad, KEY_START)) then -- check if start is pressed
|
||||
System.exit() -- Exit back to HBL
|
||||
-- Movements with bounds
|
||||
elseif (Controls.check(pad, KEY_DUP)) then
|
||||
Scene.character.position.y = Scene.character.position.y - 1
|
||||
if (Scene.character.position.y > 195) then
|
||||
Scene.character.position.y = 195
|
||||
end
|
||||
elseif (Controls.check(pad, KEY_DDOWN)) then
|
||||
Scene.character.position.y = Scene.character.position.y + 1
|
||||
if (Scene.character.position.y < 5) then
|
||||
Scene.character.position.y = 5
|
||||
end
|
||||
elseif (Controls.check(pad, KEY_DRIGHT)) then
|
||||
Scene.character.position.x = Scene.character.position.x + 1
|
||||
if (Scene.character.position.x > 355) then
|
||||
Scene.character.position.x = 355
|
||||
end
|
||||
elseif (Controls.check(pad, KEY_DLEFT)) then
|
||||
Scene.character.position.x = Scene.character.position.x - 1
|
||||
if (Scene.character.position.x < 5) then
|
||||
Scene.character.position.x = 5
|
||||
end
|
||||
end
|
||||
end
|
||||
-- !SECTION Controls check
|
||||
|
||||
local mainGUI = function ()
|
||||
-- Load the current scene
|
||||
local isBackground = Scene.currentScene[1]
|
||||
local isCharacter = Scene.currentScene[2]
|
||||
-- Draw the background
|
||||
if (isBackground) then
|
||||
Screen.fillRect(5, 395, 5, 235, Color.new(255, 0, 0), TOP_SCREEN)
|
||||
end
|
||||
-- Draw the character
|
||||
if (isCharacter) then
|
||||
Screen.drawImage(Scene.character.position.x, Scene.character.position.y,
|
||||
Scene.character.imageLoaded, TOP_SCREEN)
|
||||
end
|
||||
-- Draw the images listed in the imagesToDraw table
|
||||
for i, image in pairs(Scene.imagesToDraw) do
|
||||
-- REVIEW Should the element be placed in the scene here with 'i'?
|
||||
Screen.drawImage(image.StartingPosition[0], image.StartingPosition[1],
|
||||
image.Image, image.Screen)
|
||||
end
|
||||
end
|
||||
|
||||
-- SECTION Methods
|
||||
local isElement = function (x, y)
|
||||
if (Scene.environment.matrix[x][y].Element == nil) then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local elementPosition = function (elementName)
|
||||
if (elementsTable[elementName] == nil) then
|
||||
return nil
|
||||
end
|
||||
return elementsTable[elementName]
|
||||
end
|
||||
|
||||
local placeElement = function (x, y, element, imagePath)
|
||||
local screen = element.screen or TOP_SCREEN
|
||||
-- Ensure the element is not already placed
|
||||
if (elementPosition(element.name) ~= nil) then
|
||||
return false, "alreadyplaced" -- Element already placed
|
||||
end
|
||||
-- Ensure the tiles are empty
|
||||
for i = x + 1, x + element.width do
|
||||
for j = y + 1, y + element.height do
|
||||
if isElement(x, y) then
|
||||
return false, "notempty" -- Tile is not empty
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Loading the image
|
||||
local imageObject = Screen.loadImage(System.currentDirectory() .. imagePath)
|
||||
-- Setting the starting cell
|
||||
Scene.environment.matrix[x][y].Element = element.name
|
||||
Scene.environment.matrix[x][y].Type = element.type
|
||||
Scene.environment.matrix[x][y].Collision = element.collision
|
||||
Scene.environment.matrix[x][y].StartingPosition = {x, y}
|
||||
Scene.environment.matrix[x][y].Size = {element.width, element.height}
|
||||
Scene.environment.matrix[x][y].Image = imageObject
|
||||
Scene.environment.matrix[x][y].Screen = screen
|
||||
Scene.environment.matrix[x][y].Properties = element.properties
|
||||
-- Filling the matrix with the element
|
||||
for i = x + 1, x + element.width do
|
||||
for j = y + 1, y + element.height do
|
||||
Scene.environment.matrix[i][j] = Scene.environment.matrix[x][y]
|
||||
end
|
||||
end
|
||||
-- Adding the element to the elements table
|
||||
elementsTable[element.name] = {x, y}
|
||||
return true, "placed"
|
||||
end
|
||||
|
||||
local removeElement = function (elementName)
|
||||
-- Getting the element coordinates
|
||||
local coordinates = elementPosition(elementName)
|
||||
-- Check if the element is in the elements table
|
||||
if (coordinates == nil) then
|
||||
return
|
||||
end
|
||||
local x = coordinates[1]
|
||||
local y = coordinates[2]
|
||||
-- Setting the starting cell
|
||||
Scene.environment.matrix[x][y] = {emptyElement}
|
||||
-- Filling the matrix with the element
|
||||
for i = x + 1, x + element.width do
|
||||
for j = y + 1, y + element.height do
|
||||
Scene.environment.matrix[i][j] = Scene.environment.matrix[x][y]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local checkTileCollision = function (x, y)
|
||||
if (Scene.environment.matrix[x][y].Collision) then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
-- !SECTION Methods
|
||||
|
||||
local mainLoop = function ()
|
||||
Screen.waitVblankStart() -- Screen related stuff
|
||||
Screen.refresh() -- Other Screen related stuff
|
||||
Screen.clear(TOP_SCREEN) -- Clear top screen
|
||||
Screen.clear(BOTTOM_SCREEN) -- Clear bottom screen
|
||||
-- Keypress handling
|
||||
keyEvents() -- Check for key events
|
||||
-- Elements on screen
|
||||
mainGUI()
|
||||
Screen.flip() -- More screen related stuff
|
||||
end
|
||||
|
||||
-- START MAIN LOGIC
|
||||
initialLoad()
|
||||
|
||||
-- Continuously loop
|
||||
while (true) do
|
||||
mainLoop() -- Draw to screen
|
||||
end
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user